package com.cskaoyan.javase.oop2.encapsulate._1extends._8hidden._0basic;

/**
 * 属性的隐藏
 * 什么是属性的隐藏呢?
 *
 * 父子类存在同名成员变量的情况下，创建子类对象用子类引用指向
 * 再用这个子类引用访问父子类同名成员变量会得出子类中的结果
 * 而父类中的同名成员变量仍然可以通过Getter方法访问
 *
 * 以上这种现象,说明父类中的同名成员变量仍然是存在的,仍然可以访问到
 * 被称之为"属性的隐藏"
 *
 * 为什么隐藏?
 * 这是Java语法中"对象名.成员变量"的访问机制决定的,决定了是隐藏.
 *
 * (重点)接下来就是重点,研究一下"对象名.成员变量名"的访问机制
 *
 * 研究这个访问机制,首先我们要明确"对象名"的来源,有几种:
 *      1.父类引用指向父类对象
 *      2.子类引用指向子类对象
 *      3.父类引用指向子类对象
 *
 * 其次,研究"对象名.成员变量"的访问机制,从以下两个角度来研究:
 *      1.对象名.的访问范围,究竟能够访问父子类中哪些成员变量
 *      2.对象名.的访问结果,访问结果究竟是什么
 *
 * 首先,研究对象名.成员变量的访问范围
 *       1.父类引用指向父类对象
 *          访问范围仅限于父类中定义的成员变量
 *
 *       2.子类引用指向子类对象
 *          访问范围是父类 + 子类
 *
 *       3.父类引用指向子类对象
 *          访问范围仅限于父类中定义的成员变量
 *
 * 以上,得出结论:
 *      "对象名.成员变量"的访问范围是由"引用的数据类型"来决定的:
 *          如果引用是子类类型, 那么范围是父类 + 子类
 *          如果是引用是父类类型, 那么范围就是父类自身,无法访问子类
 *
 * 访问范围是一个编译上的概念,如果能够访问就通过编译,否则就会编译报错写
 * 换句话说编译器认为引用的类型就是对象的类型。
 *
 * 编译器在确定访问范围时,可以从引用的数据类型中向上找它的父类,直到找到最顶层Object:
 *      如果找到,说明有这个成员,就允许访问
 *      如果找不到,说明没有这个成员,就编译报错
 * 反之,是绝无可能向下找子类
 * 因为子类继承父类是通过extends关键字直接声明的,但父类并不知道它有这个子类
 * 子类知道自己的"爸爸"是谁
 * 但"爸爸"并不知道它有这个"儿子"，甚至都不知道自己有几个"儿子"，或者有没有"儿子"。
 *
 *
 * 其次,研究对象名.成员变量的访问结果
 *      1.父类引用指向父类对象
 *          访问的结果是父类中成员变量的结果
 *
 *      2.子类引用指向子类对象
 *          访问的结果是子类中成员变量的结果
 *
 *      3.父类引用指向子类对象
 *          访问的结果是父类中成员变量的结果
 *
 * 以上,总结,"对象名.成员变量"的访问结果也只需要看引用的数据类型就够了,结果是引用的类型中该成员变量的结果
 *
 * 综合对象名点访问成员变量的范围和结果，发现：
 * 都是根据引用的数据类型来决定的，无需考虑是何种对象。
 *
 * @since 15:00
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        /*Son s = new Son();
        System.out.println(s.a);
        System.out.println(s.getA());*/

        // 1.父类引用指向父类对象
        Father f = new Father();
        System.out.println(f.a);
        System.out.println(f.fatherA);
        // f.sonA

        // 2.子类引用指向子类对象
        Son s = new Son();
        System.out.println(s.a);
        System.out.println(s.fatherA);
        System.out.println(s.sonA);

        // 3.父类引用指向子类对象
        Father fs = new Son();
        System.out.println(fs.fatherA);
        System.out.println(fs.a);
        // fs.sonA
        // 向下转型,强转就不算能够访问了,所以这个是不能访问的
        // System.out.println(((Son) fs).sonA);
    }
}

class Father {
    // 父子类同名的成员变量
    int a = 10;
    // 独属于父类的成员变量
    int fatherA = 100;

    public int getA() {
        return a;
    }
}

class Son extends Father {
    // 父子类同名的成员变量
    int a = 20;
    // 独属于子类的成员变量
    int sonA = 200;

}